FUNCIONES II

Las funciones son el método principal de organización y reutilización de código. Las funciones tienen un nombre y se declaran con la palabra reservada def y devuelve un valor usando la palabra reservada return.

También tienen una lista de argumentos:

  • posicionales
  • por clave
  • argumentos agrupados
    • tupla de argumentos posicionales (*args)
    • diccionario de argumentos accedidos por clave (**kwargs)

Los argumentos por clave se usan para indicar valores por defecto y siempre se sitúan después de los argumentos posicionales.


In [1]:
# Función que suma 3 números y devuelve el resultado
# 2 argumentos posicionales (x, y) y 2 por clave (z1, z2)
def suma_varios(x, y, z1=2, z2=4):
    m = x + y + z1 + z2
    return m

In [2]:
resultado1 = suma_varios(2, 3)
resultado2 = suma_varios(2, 3, z2=1)
resultado1, resultado2


Out[2]:
(11, 8)

Usamos *args para representar una tupla arbitraria de argumentos agrupados. No es necesario que el nombre sea args:


In [3]:
def suma_varios(x, y, *otros):
    print( "x:", x )
    print( "y:", y )
    print("otros:", otros)
    suma = 0
    for i in otros:
        suma = suma + i
    return x + y + suma

suma_varios(1, 2, 1, 3, 5, 7, 11)


x: 1
y: 2
otros: (1, 3, 5, 7, 11)
Out[3]:
30

Se pueden definir los argumentos agrupados después de los argumentos posiciones y por clave. Usamos **kwargs para representar una lista arbitraria de argumentos agrupados representada como un diccionario. Como en el caso anterior, no es necesario que el nombre sea kwargs:


In [4]:
def suma_varios(x, y, *otros, **mas):
    print( "x:", x )
    print( "y:", y )
    print("otros:", otros)
    print("mas:", mas)
    if mas.get('borrame'):
        x = 0
        print('x vale %d' % x)

In [5]:
suma_varios(1,2,3,4,5,6,7,8,9, cien = 100 , mil = 1000, borrame = True)


x: 1
y: 2
otros: (3, 4, 5, 6, 7, 8, 9)
mas: {'cien': 100, 'mil': 1000, 'borrame': True}
x vale 0


VARIABLES Y PASO POR REFERENCIA

En una asignación de un valor a una variable, se crea una referencia al objeto que se encuentra en el lado derecho de la asignación. Esto es muy importante entenderlo cuando se trabaja con grandes volúmenes de datos.


In [6]:
a = [1, 3, 5]
a


Out[6]:
[1, 3, 5]

In [7]:
b = a
b


Out[7]:
[1, 3, 5]

Ambas viariables 'a' y 'b' referencian al mismo objeto (la lista [1, 3, 5]). Si se modifica cualquiera de ellos, se modifican los dos.


In [8]:
a.append(7)
b


Out[8]:
[1, 3, 5, 7]

En Python el paso de argumentos a una función se hace por referencia, mientras que en otros lenguajes se permite paso por valor y paso por referencia.


In [9]:
def cambia(lista, num):
    lista.append(num)
a = [1, 2, 4]
cambia(a, 9)
a


Out[9]:
[1, 2, 4, 9]


FUNCIONES COMO ARGUMENTOS DE OTRAS FUNCIONES

Supongamos que tenemos una lista de ciudades que necesitamos 'limpiar' o 'formatear'.


In [10]:
ciudades = ['   Madrid', ' BARcelona', 'SeVILLA  ' ]

Para dar un formato uniforme a esta lista antes de realizar otras tareas de análisis, es necesario transformarla eliminado espacios en blanco y transformando cada nombre a tipo título.


In [11]:
# Primera opción
def formatear(lista):
    resultado = []
    for ciudad in lista:
        ciudad = ciudad.strip()     # elimina espacios en blanco
        ciudad = ciudad.title()     # tipo título        
        resultado.append(ciudad)
    return resultado

In [12]:
formatear(ciudades)


Out[12]:
['Madrid', 'Barcelona', 'Sevilla']

Una alternativa más flexible consiste en crear una lista de operaciones a realizar y posteriormente aplicarla a la lista de ciudades:


In [13]:
# Segunda opción
operaciones = [str.strip, str.title]

def formatear(lista, operaciones):
    resultado = []
    for ciudad in lista:
        for op in operaciones:
            ciudad = op(ciudad)    
        resultado.append(ciudad)
    return resultado
formatear(ciudades, operaciones)


Out[13]:
['Madrid', 'Barcelona', 'Sevilla']

In [14]:
# Tercera opción
def formatear(lista, fun):
    resultado = []
    for ciudad in lista:
        nueva = fun(ciudad)
        resultado.append(nueva)
    return resultado
formatear(ciudades, str.upper)


Out[14]:
['   MADRID', ' BARCELONA', 'SEVILLA  ']

El uso de funciones como argumentos de otras funciones es una característica de los lenguajes funcionales. La función map de los lenguajes funcionales también está accesible en Python. Esta función aplica una función a una colección de objetos:


In [15]:
# Python 3.5 map devuelve un objeto iterable 
m1 = map(str.strip , ciudades)
list(m1)


Out[15]:
['Madrid', 'BARcelona', 'SeVILLA']

In [16]:
m2 = map(str.title, map(str.strip , ciudades))
list(m2)


Out[16]:
['Madrid', 'Barcelona', 'Sevilla']


FUNCIONES ANÓNIMAS (LAMBDA FUNCTIONS)

Las funciones anónimas son aquellas que no tiene nombre y se refieren a una única instrucción. Se declaran con la palabra reservada lambda. Son funciones cortas.


In [17]:
# función normal
def producto(a):  
    return a * 2

# la función anónima equivalente:
resultado = lambda a: a * 2

producto(6), resultado(6)


Out[17]:
(12, 12)
  • Las funciones lambda se utilizan mucho en análisis de datos ya que es muy usual transformar datos mediante funciones que tienen a otras funciones en sus argumentos.
  • Se usan funciones lambda en lugar de escribir funciones normales para hacer el código más claro y más corto.

In [18]:
# mutiplicar por 2 todos los números de una lista
s = [1, 2, 3, 4]
def doble(lista, f):
    """  Devuelvo una nueva lista definida por comprensión """
    return [ f(x) for x in lista ]

In [19]:
doble(s, producto)


Out[19]:
[2, 4, 6, 8]

Pero el mismo efecto lo conseguimos mediante una función anónima, evitando así la definición de la función producto:


In [20]:
doble(s, lambda x: x * 2)


Out[20]:
[2, 4, 6, 8]

In [ ]: